package db

import (
	"database/sql/driver"
	"pmservice/graph/model"
	"strings"

	gonanoid "github.com/matoous/go-nanoid/v2"
	"gorm.io/gorm"
)

type PocList []string

func (v *PocList) Scan(val interface{}) error {
	s := val.(string)
	if len(s) > 0 {
		ss := strings.Split(s, "|")
		*v = ss
	} else {
		*v = []string{}
	}
	return nil
}

func (v PocList) Value() (driver.Value, error) {
	str := strings.Join(v, "|")
	return str, nil
}

type Doctor struct {
	gorm.Model
	UID      string
	Hospital string
	Account  string
	Password string
	Name     string
	Mobile   string
	Pocs     PocList
}

func (Doctor) TableName() string {
	return "doctor"
}

func (d *Doctor) FromGQLNew(in *model.DoctorNew) {
	d.Name = in.Name
	d.Mobile = in.Mobile
	d.Hospital = in.Hosuid
	d.Account = in.Account
	d.Password = in.Password
}

func (d *Doctor) FromGQLEdit(in *model.DoctorEdit) []string {
	fields := []string{}
	if in.Name != nil {
		d.Name = *in.Name
		fields = append(fields, "name")
	}

	if in.Mobile != nil {
		d.Mobile = *in.Mobile
		fields = append(fields, "mobile")
	}

	if in.Account != nil {
		d.Account = *in.Account
		fields = append(fields, "account")
	}
	return fields
}

func (d *Doctor) ToGQL() *model.Doctor {
	return &model.Doctor{
		UID:      d.UID,
		Account:  d.Account,
		Password: d.Password,
		Name:     &d.Name,
		Mobile:   &d.Mobile,
	}
}

func DoctorGet(dbs *gorm.DB, uid string) *Doctor {
	d := Doctor{}
	result := dbs.Where("uid=?", uid).Take(&d)
	if result.Error != nil {
		return nil
	}
	return &d
}

func DoctorGetByAccount(dbs *gorm.DB, hosuid string, account string) *Doctor {
	d := Doctor{}
	result := dbs.Where("account=?", account).Take(&d)
	if result.Error != nil {
		return nil
	}
	return &d
}

// 检查账号名是否已被使用
func DoctorExist(dbs *gorm.DB, hosuid string, except string, account string) bool {
	d := Doctor{}
	result := dbs
	if except == "" {
		result = dbs.Where("account=? AND hospital=?", account, hosuid).Take(&d)
	} else {
		result = dbs.Where("account=? AND hospital=? AND uid!=?", account, hosuid, except).Take(&d)
	}
	return result.Error == nil && result.RowsAffected > 0
}

func DoctorNew(dbs *gorm.DB, input *model.DoctorNew) (*Doctor, error) {
	d := Doctor{
		UID: gonanoid.Must(),
	}
	d.FromGQLNew(input)
	// 创建账号
	result := dbs.Create(&d)
	if result.Error != nil {
		return nil, result.Error
	}
	return &d, nil
}

func DoctorSave(dbs *gorm.DB, hosuid string, uid string, input *model.DoctorEdit) bool {
	d := Doctor{}
	fields := d.FromGQLEdit(input)
	result := dbs.Where("uid=? AND hospital=?", uid, hosuid).
		Select(fields).
		Updates(&d)
	if result.Error != nil || result.RowsAffected == 0 {
		return false
	}
	return true
}

func DoctorDel(dbs *gorm.DB, uid string) bool {
	result := dbs.Where("uid=?", uid).Delete(&Doctor{})
	return result.Error == nil && result.RowsAffected > 0
}

func DoctorLogin(dbs *gorm.DB, account string, password string) *Doctor {
	d := Doctor{}
	result := dbs.Where("account=? AND password=?", account, password).Take(&d)
	if result.Error != nil {
		return nil
	}
	return &d
}

func DoctorUpdatePassword(dbs *gorm.DB, uid string, oldpass string, newpass string) bool {
	d := Doctor{
		UID:      uid,
		Password: newpass,
	}
	fields := []string{"password"}
	result := dbs
	result = result.Where("uid=? AND password=?", uid, oldpass).
		Select(fields).
		Updates(&d)
	if result.Error != nil || result.RowsAffected == 0 {
		return false
	}
	return true
}

func DoctorSearch(dbs *gorm.DB, cond model.DoctorSearchCond) (doctors []*Doctor, total int64) {
	result := dbs.Where("hospital=?", cond.Hosuid)
	result.Model(&Doctor{}).Count(&total)
	if cond.Page != nil {
		result = result.Order("id DESC").Limit(cond.Page.Number).Offset(cond.Page.Offset).Find(&doctors)
	} else {
		result = result.Order("id DESC").Find(&doctors)
	}

	if result.Error != nil {
		return nil, 0
	}

	return doctors, total
}

func DoctorMonitorPoc(dbs *gorm.DB, uid string, pocuid string) bool {
	poc := PocGet(dbs, pocuid)
	if poc == nil {
		return false
	}
	d := DoctorGet(dbs, uid)
	if d == nil {
		return false
	}
	for _, v := range d.Pocs {
		if v == pocuid {
			return true // 已经存在
		}
	}
	d.Pocs = append(d.Pocs, pocuid)
	fields := []string{"pocs"}
	result := dbs
	result = result.Where("uid=?", uid).
		Select(fields).
		Updates(&d)
	if result.Error != nil || result.RowsAffected == 0 {
		return false
	}
	return true
}

func DoctorUnmonitorPoc(dbs *gorm.DB, uid string, pocuid string) bool {
	d := DoctorGet(dbs, uid)
	if d == nil {
		return false
	}
	found := false
	pocs := []string{}
	for _, v := range d.Pocs {
		if v == pocuid {
			found = true
		} else {
			pocs = append(pocs, v)
		}
	}
	if !found { // 不存在
		return false
	}
	d.Pocs = pocs
	fields := []string{"patients"}
	result := dbs
	result = result.Where("uid=?", uid).
		Select(fields).
		Updates(&d)
	if result.Error != nil || result.RowsAffected == 0 {
		return false
	}
	return true
}
